09.实现自动化引擎之Jenkins Pipeline声明式语法

介绍

Jenkins pipeline(流水线)是Jenkins 2.x 或以上版本提供的一套插件,是实现jenkins自动化引擎的另一种强大工具。它支持实现和集成持续交付流水线到 Jenkins。对Jenkins 流水线的定义可以通过在Jenkins经典UI中直接输入基本的pipeline script;也可以被写在一个文本文件中 ( Jenkinsfile),该文件可以被提交到项目的源代码仓库的根目录中,通过配置pipeline项目下载jenkinsfile文件并自动执行

pipeline脚本可以使用两种语法进行编写: 声明式和脚本式。声明式和脚本式的流水线从根本上是不同的,但都是建立在底层流水线的子系统上的,使用声明式流水线可以利用Jenkins流水线更好的特性:

  • 相比脚本式的流水线语法,它提供更丰富的语法特性。
  • 相比脚本式的流水线语法,声明式的流水线编写和读取代码更容易,维护更简单。

脚本式流水线为Jenkins用户提供了大量的灵活性和可扩展性。但是 Groovy学习路线通常不适合团队的所有成员; 因此创造了声明式流水线来为编写Jenkinsfile提供一种更简单、更有结构性的语法。声明式流水线鼓励声明式编程模型。 而脚本化流水线遵循一个更趋近于命令式的编程模型 ,它们的主要区别在于语法和灵活性。

虽然他们都是”流水线即代码“的基础,但是创建 Jenkinsfile并提交它到源代码仓库中提供了一些好处:

  • 自动地为所有分支创建流水线构建过程并拉取请求。
  • 在流水线上代码复查/迭代 (以及剩余的源代码)。
  • 对流水线进行审计跟踪。
  • 该流水线的真正的源代码可以被项目的多个成员查看和编辑。

下面简单介绍一下这两种流水线语法模板:

脚本式流水线

在脚本式流水线语法中, 使用一个或多个 node 块来指定代理主机来执行流水线中的核心任务。 它根据在jenkins系统内配置的代理主机的标签选择主机,该配置不是必须的。

# 如果没有指定slave主机,则默认在master主机执行任务
node {  

    stage('Build') { 

    }
    stage('Test') { 

    }
    stage('Deploy') { 

    }
}

说明

  • node 是脚本式流水线的一种特定语法,它指示 Jenkins 在任何可用的代理/节点上执行流水线 (包含在其中的任何stage)。

  • stage('Build')定义 “Build” 阶段,stage块在脚本式流水线语法中是可选的,不过在脚本式pipeline中使用stage块 ,在执行时可以清楚的显示每个stage的任务子集,所以stage块还是建议使用。

  • 上面的stage括号内的字符串(Build)为自定义的,不一定非得根据官方给出的范例填写,方便自己区分即可。

声明式流水线

示例如下:

pipeline { 
    agent any 
    stages {
        stage('Build') { 
            steps { 
                sh 'pwd' 
            }
        }
        stage('Test'){
            steps {
                sh 'make check'
                junit 'reports/**/*.xml' 
            }
        }
        stage('Deploy') {
            steps {
                sh 'deploy'
            }
        }
    }
}

说明

  • pipeline {}是声明式流水线的特定语法,他定义了包含执行整个流水线的所有内容;

  • agent是声明式流水线中必须的关键字,它指定一个执行器或者代理节点用来执行流水线;

  • stage{} 描述要执行的任务的语法块。一个stage块包含一个steps;

  • steps{} 是声明式流水线的特定语法,它描述了在这个 stage 中要运行的步骤;

  • sh 用来执行shell命令 ;

由上面的简单示例可以发现,声明式限制了用户使用更严格和预定义的结构, 使其成为更简单的持续交付流水线的理想选择。而脚本式提供了很少的限制, 以至于对脚本和语法的唯一限制往往是由Groovy子集本身定义的,而不是任何特定于流水线的系统, 这使他成为权利用户和那些有更复杂需求的人的理想选择。 但是在后续使用中会发现,在使用某些插件的情况下,使用脚本式流水线会比声明式流水线更加灵活好用。

基本概念

流水线的代码定义了整个的交付和部署过程,在使用使用过程中,流水线通常包括测试(test)、构建(build)和交付部署(Deploy)应用程序等步骤 。一个完整的 pipeline脚本由一系列pipeline块组成, 这些块的主要组成部分如下:

- node/agent(节点)

node和agent关键字都是用来指定jenkins的代理节点 ,它是jenkins环境的一部分并且可以用来执行pipeline。node是脚本化流水线语法的关键部分,agent是声明式流水线语法的关键部分

- stages/stage

stages 块定义了在整个流水线中的执行任务的不同子集(比如 “Build”, “Test” 和 “Deploy” 阶段),每一个子集通常是一段代码块,在以后可能会遇到stage,一个stages可以包含多个stage。

- steps

一个单一的任务, 它告诉Jenkins 在特定的阶段要做什么。 通常放在stage下面,也是由一段代码或者一个模块构成。

了解了基本概念,下面对前面提到的两种类型的pipeline语法进行一个简单的介绍。

声明式 pipeline语法

所有有效的声明式流水线代码必须包含在一个 pipeline 块中, 比如:

pipeline {
    ....
}

在声明式流水线中有效的基本语句和表达式遵循与 Groovy的语法同样的规则, 但是有以下例外:

  • 流水线顶层必须是一个 block块: pipeline {}
  • 没有用分号作为语句分隔符,每条语句都必须在自己的行上。

agent

agent ,声明式流水线设置代理节点的指令,用于指定执行pipeline脚本的slave节点或其他机器。agent部分可以放在 pipeline 块的顶层被定义, 也可以放在 stage 块下定义。

参数

为了适用各种可能的代理节点, agent 部分支持一些不同类型的参数。这些参数可以应用在pipeline块的顶层, 也可以应用在stage 指令内部。

any

在任何可用的代理上执行流水线或stage。例如: agent any

none

当在 pipeline 块的顶部没有配置全局的agent代理时, 该关键字将会被应用到整个流水线中,并且每个 stage 部分都需要定义自己的 agent 部分。如果指定了agent不为none,并且在stage也定了agent,则默认使用在stage中定义的agent。

label

可以通过lable关键字指定设置了label的Jenkins节点。 例如: agent { label 'jenkins-slave1' },该jenkins-slave1为在系统中添加的jenkins slave节点,并且该节点的标签为jenkins-slave1

node

agent { node { label 'labelName' } }agent { label 'labelName' } 效果是一样的, 但是 node 允许额外的选项 (比如 customWorkspace ,下面会说到)。

docker

使用给定的镜像启动一个容器作为全局或某个stage执行的环境。该镜像将在指定的node或者通过label关键字指定的节点上动态的生成容器来执行流水线操作。也可以理解为jenkins的动态slave节点。比如: agent { docker 'maven:3-alpine' }

docker关键字也可以添加 args 参数,添加的参数可能包含直接传递到 docker run 时调用的参数,比如挂载目录。

  agent {
      docker {
          image 'maven:3-alpine'
          label 'my-defined-label'
          args  '-v /tmp:/tmp'
      }
  }

dockerfile

除了上面直接使用docker镜像启动容器以外,还可以使用通过 Dockerfile 构建的容器。 通常将Dockerfile放到源代码仓库的根目录下 : agent { dockerfile true }

如果Dockerfile不在根目录下,也可以在其它目录下构建, 需要使用 dir 参数来指定dockerfile目录:

  agent { dockerfile {dir 'someSubDir' } }

如果 Dockerfile 有另一个名称, 你可以使用 filename 选项指定该文件名。

如果构建时需要传递参数到dockerfile,可以使用 additionalBuildArgs 选项提交,比如:

  agent { dockerfile {additionalBuildArgs '--build-arg foo=bar' } }

将上面的综合起来使用docker命令为 docker build -f Dockerfile.build --build-arg version=1.0.2 ./build/ ,使用pipeline代码为:

  agent {
      dockerfile {
          filename 'Dockerfile.build'
          dir 'build'
          label 'my-defined-label'
          additionalBuildArgs  '--build-arg version=1.0.2'
      }
  }

kubernetes

该关键字用于在kubenretes集群内动态的启动一个pod作为jenkins的slave节点去执行流水线操作,流水线执行完毕后pod自动销毁,官网给出的示例如下:

  agent {
      kubernetes {
          label podlabel
          yaml """
  kind: Pod
  metadata:
    name: jenkins-slave
  spec:
    containers:
    - name: kaniko
      image: gcr.io/kaniko-project/executor:debug
      imagePullPolicy: Always
      command:
      - /busybox/cat
      tty: true
      volumeMounts:
        - name: aws-secret
          mountPath: /root/.aws/
        - name: docker-registry-config
          mountPath: /kaniko/.docker
    restartPolicy: Never
    volumes:
      - name: aws-secret
        secret:
          secretName: aws-secret
      - name: docker-registry-config
        configMap:
          name: docker-registry-config
  """
     }

看着有些复杂凌乱,但实际使用kubernetes agent的时候,如果用到脚本式语法,可能就会比这个简单的多。

agent的一些常见选项

有一些选项关键字可应用于有多个 agent 的pipeline。

label

该选项用于全局流水线或个别的 stage。该选项对 node, dockerdockerfile都可用,但是如果使用 node参数时需要使用lable。

customWorkspace

自定义工作区,可以应用在 agent 的所有流水线或者一些 stage。自定义工作区存在于节点工作区根目录下, 它既可以是一个相对路径, 也可以是一个绝对路径。比如:

  agent {
      node {
          label 'my-defined-label'
          customWorkspace '/some/other/path'
      }
  }

该选项对 node, dockerdockerfile 有用 。

示例

在指定的slave节点上构建服务

pipeline {
    agent none 
    stages {
        stage('Build') {
            agent { node { label 'master' } } 
            steps {
                sh 'hostname'
            }
        }
        stage('Test') {
            agent { node { label 'slave1' } } 
            steps {
                sh 'hostname'
            }
        }
    }
}

在一个给定的容器镜像(maven:3-alpine)上启动一个容器并执行定义在流水线中的所有步骤 。

pipeline {
    agent { docker 'maven:3-alpine' } 
    stages {
        stage('build') {
            steps {
                sh 'mvn clean install'
            }
        }
    }
}

在指定的stage阶段根据给定的镜像启动一个容器并执行定义在流水线中的步骤。

pipeline {
    agent none 
    stages {
        stage('Build') {
            agent { docker 'maven:3-alpine' } 
            steps {
                echo 'Hello, Maven'
                sh 'mvn --version'
            }
        }
        stage('Test') {
            agent { docker 'openjdk:8-jre' } 
            steps {
                echo 'Hello, JDK'
                sh 'java -version'
            }
        }
    }
}

说明

在流水线最顶层定义了 agent none 会强制 stage 部分强制定义他自己的 agent 部分。

stages

包含一个或多个 stage 指令,pipeline所做的所有工作都会封装在一个或多个 stage 指令中。 建议 stages 至少包含一个 stage 指令,示例如下:

pipeline {
    agent any
    stages { 
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

需要说明的是,stages指令是声明式脚本中特有的,包括下面即将说到的steps,也是声明式脚本中特有的,脚本式的流水线中只有stage指令。

steps

steps 部分是在给定的 stage 中定义的一个或多个step(代码),它包含一个完整的step列表, 而在step里可以定义环境变量,执行脚本等操作,如下示例:

pipeline {
    agent any
    stages {
        stage('Example') {
            steps { 
                echo 'Hello World'
            }
            steps { 
                script{
                 sh 'hostname'
                }
            }
        }
    }
}

需要注意的是,在声明式语法中,steps块是必须的。

options

options 指令用于在流水线内部配置特定与全局pipeline或者特定stage的选项。 流水线提供了许多这样的选项,比如 buildDiscarder,该参数可以设置保存job的构建记录的历史数量和要保存的时间;该选项除了可以使用内置参数外,也可以使用由插件提供的参数, 比如 podTemplate

全局选项

buildDiscarder

用于设置在UI中显示流水线执行的历史数量和保存的天数。例如: options { buildDiscarder(logRotator(numToKeepStr: '1')) }

disableConcurrentBuilds

不允许同时执行流水线。 可被用来防止同时访问共享资源等。 例如: options { disableConcurrentBuilds() }

skipDefaultCheckout

agent 指令中,跳过从源代码库中检出代码步骤。例如: options { skipDefaultCheckout() }

skipStagesAfterUnstable

如果构建状态变成UNSTABLE,则跳过该阶段。例如: options { skipStagesAfterUnstable() }

checkoutToSubdirectory

将代码保存到工作目录的子目录。例如: options { checkoutToSubdirectory('foo') }

timeout

设置流水线运行的超时时间,如果超过该时间,Jenkins将中止流水线。例如: options { timeout(time: 1, unit: 'HOURS') }

retry

在执行失败时,重新执行整个流水线的指定次数。 例如: options { retry(3) }

timestamps

用于在控制台输出流水线各步骤执行时的当前时间, 例如: options { timestamps() }

示例如下:

pipeline {
    agent any
    options {
        timeout(time: 1, unit: 'HOURS') 
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

该示例用于设置流水线执行的超时时间。

stage

options指令除了可以定义全局的选项参数外,也可以定义stage级别的options选项参数。 stage 级别的 options 只能包括 retry, timeout, 或 timestamps 等选项,或与 stage 相关的声明式选项,如 skipDefaultCheckout

stage中定义的options 指令中的参数在进入 agent 之前被调用或在 when 条件出现时进行检查。

可选的stage选项

skipDefaultCheckout

agent 指令中跳过默认的从源代码仓库检出代码。例如: options { skipDefaultCheckout() }

timeout

设置此阶段的超时时间,如果超过该时间, Jenkins 会终止该阶段。 例如: options { timeout(time: 1, unit: 'HOURS') }

retry

在job失败时, 重新执行测次数。 例如: options { retry(3) }

timestamps

用于在控制台输出流水线各步骤执行时的当前时间。例如: options { timestamps() }

示例如下

pipeline {
    agent any
    stages {
        stage('Example') {
            options {
                timeout(time: 1, unit: 'HOURS') 
            }
            steps {
                echo 'Hello World'
            }
        }
    }
}

environment

environment 指令用来定义一个或多个由key=value键值对组成的为所有stage使用的环境变量,至于该环境变量全局的还是特定stage的取决于 environment 指令在流水线内定义的位置。

示例如下:

pipeline {
    agent any
    environment {
        unit_test = 'true'
        version = "v1"
        JAVA_HOME='/data/jdk'
    }
    stages {
        stage('Example') {
            steps('test1') {
                script {
                    if ( unit_test ) {
                       echo version
                    }
                }
                echo "$JAVA_HOME"
            }
        }
    }
}

该示例定义了三个全局的环境变量。

environment指令也可以通过 credentials() 方法引用事先在jenkins中创建的凭据。该方法支持的类型如下:

Secret Text

指定的环境变量将设置为secret文本内容。

Secret File

指定的环境变量将设置为临时创建的文件文件。

Username and password- 指定的环境变量将被设置为username:password,另外两个环境变量将被自动定义:MYVARNAME_USRMYVARNAME_PSW

SSH与Private Key- 指定的环境变量将被设置为临时创建的SSH密钥文件,并且可能会自动定义两个其他环境变量:MYVARNAME_USRMYVARNAME_PSW

如下示例:

pipeline {
    agent any
    environment { 
        CC = 'clang'
    }
    stages {
        stage('test-secret') {
            environment { 
                SERVICE_CREDS = credentials('3d0e85b7-30cd-451d-bf9e-e6d87f6c9686')
                SSH_CREDS = credentials('160-ssh')
            }
            steps {
                sh 'printenv'
                sh 'echo "Service user is $SERVICE_CREDS_USR"'
                sh 'echo "Service password is $SERVICE_CREDS_PSW"'
                sh 'echo "SSH user is $SSH_CREDS_USR"'
                sh 'echo "SSH passphrase is $SSH_CREDS_PSW"'
            }
        }
        stage('test-usrename-password') {
            environment { 
                SERVICE_CREDS = credentials('auth_harbor')
                SSH_CREDS = credentials('160-ssh')
            }
            steps {
                sh 'echo "Service user is $SERVICE_CREDS_USR"'
                sh 'echo "Service password is $SERVICE_CREDS_PSW"'
                sh 'echo "SSH user is $SSH_CREDS_USR"'
                sh 'echo "SSH passphrase is $SSH_CREDS_PSW"'
            }
        }
    }
}

parameters

parameters (参数)指令提供在触发流水线时应该提供的参数列表。这些指定参数的值可通过 params 对象提供给流水线steps,可用的参数类型如下:

string

字符串类型的参数,比如:parameters { string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '') }

text

文本类型的参数, 可以包含多行内容, 比如: parameters { text(name: 'DEPLOY_TEXT', defaultValue: 'One\nTwo\nThree\n', description: '') }

booleanParam:布尔类型的参数, 比如:parameters { booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '') }

choice:选择类型的参数, 比如:parameters { choice(name: 'CHOICES', choices: ['one', 'two', 'three'], description: '') }

password:密码类型测参数, 比如:parameters { password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password') }

示例如下:

pipeline {
    agent any
    parameters {
        string(name: 'version', defaultValue: 'latest', description: 'the image version')
        text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some information about the person')
        booleanParam(name: 'test', defaultValue: true, description: 'Toggle this value')
        choice(name: 'build_number', choices: ['One', 'Two', 'Three'], description: 'the build_number')
        password(name: 'PASSWORD', defaultValue: 'mypassword', description: 'Enter a password')
    }
    stages {
        stage('print') {
            steps {
                echo " ${params.version}"
                echo " ${params.BIOGRAPHY}"
                echo "${params.test}"
                echo "${params.build_number}"
                echo "${params.PASSWORD}"
            }
        }
    }
}

说明:

name为定义的参数的名称,引用参数时通过name引用。

parameters的语法片段可以在片段生成器(后面详细介绍)中生成,如下所示:

选择好参数类型设置好参数后直接点击Generate Declarative directive即可。

triggers

triggers (触发器)指令定义了流水线被触发的自动化方法。对于与源代码集成的流水线(pipeline脚本放到源码库),可能不需要 triggers 。 当前可用的触发器是 cron, pollSCMupstream

cron- 接收crontab格式(linux crontabl)的字符串来定义要触发流水线的间隔 。

示例如下:

  pipeline {
      agent any
      triggers {
          cron('0 */4 * * 1-5')
      }
      stages {
          stage('test') {
              steps {
                  echo 'Hello World'
              }
          }
      }
  }

该pipeline会定时触发执行

pollSCM

接收cron样式的字符串来定义一个固定的间隔,在这个间隔中,Jenkins会检查新的源代码更新。如果源码存在更改,,流水线就会被重新触发。

例如:

  pipeline{
      agent any
      triggers{
          pollSCM('5 10 * * *')
      }
      stages{
          stage('test-code'){
              steps{
                  echo "周期性检查代码测试"
              }
          }
      }
  }

upstream

接受逗号分隔的job名称。 当字符串中的任何job以最小阈值结束时,流水线被重新触发。例如:

  pipeline{
      agent any
      triggers{
          upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS)
      }
      stages{
          stage('test-upstream'){
              steps{
                  echo "当job1或job2执行成功时,触发该流水线"
              }
          }
      }
  }

其中hudson.model.Result可包含以下属性:

  • ABORTED:任务被手动中止
  • FAILURE:构建失败
  • SUCCESS:构建成功
  • UNSTABL:存在一些错误,但构建没失败
  • NOT_BUILT:多阶段构建时,前面阶段问题导致后面阶段无法执行

tools

tools(工具),用来定义自动安装或者已经在jenkins系统中配置的工具。如果指定 agent none ,该操作被忽略。

支持的工具包括maven,jdk,gradle等,示例如下:

pipeline {
    agent any
    tools {
        maven 'apache-maven-3.5'
        jdk   'jdk1.8'
    }
    stages {
        stage('Example') {
            steps {
                sh 'mvn --version'
            }
        }
    }
}

需要注意的是,apache-maven-3.5 该名称为在Global Tool Configuration中定义的maven工具的名称。

when

when 指令允许流水线根据给定的条件决定是否应该执行stage。 when 指令必须包含至少一个条件, 如果 when 指令包含多个条件, 所有的子条件必须都返回True,stage才能执行。 这与子条件在 allOf 条件下嵌套的情况相同。

when包含诸多内置条件,使用如 not, allOfanyOf 的嵌套条件可以构建更复杂的条件结构,内置的条件如下:

branch

当正在构建的分支与给定的分支匹配时,执行这个stage,例如:

when { branch 'master' }

注意,这只适用于多分支流水线。

  pipeline {
      agent any
      stages {
          stage('Example Deploy') {
              when {
                  branch 'production'
              }
              steps {
                  echo 'Deploying'
              }
          }
      }
  }

environment

当指定的环境变量是给定的值时,执行这个steps 例如:

when { environment name: 'DEPLOY_TO', value: 'production' }

  pipeline {
      agent any
      stages {
          stage('Example Deploy') {
              when {
                  branch 'production'
                  environment name: 'DEPLOY_TO', value: 'production'
              }
              steps {
                  echo 'Deploying'
              }
          }
      }
  }

expression

当指定的Groovy表达式结果为true时,执行这个stage 例如:

when { expression { return params.DEBUG_BUILD } }

  pipeline {
      agent any
      stages {
          stage('Example Deploy') {
              when {
                  expression { BRANCH_NAME ==~ /(production|staging)/ }
              }
              steps {
                  echo 'Deploying'
              }
          }
      }
  }

not

当嵌套条件是错误时,执行这个stage,必须包含一个条件,例如:

when { not { branch 'master' } }

- allOf

当所有的嵌套条件都正确时,执行这个stage,必须包含至少一个条件,例如:

when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }

  pipeline {
      agent any
      stages {
          stage('Example Deploy') {
              when {
                  allOf {
                      branch 'production'
                      environment name: 'DEPLOY_TO', value: 'production'
                  }
              }
              steps {
                  echo 'Deploying'
              }
          }
      }
  }

anyOf

当至少有一个嵌套条件为真时,执行这个stage,必须包含至少一个条件,例如:

when { anyOf { branch 'master'; branch 'staging' } }

  pipeline {
      agent any
      stages {
          stage('Example Deploy') {
              when {
                  branch 'production'
                  anyOf {
                      environment name: 'DEPLOY_TO', value: 'production'
                      environment name: 'DEPLOY_TO', value: 'staging'
                  }
              }
              steps {
                  echo 'Deploying'
              }
          }
      }
  }

equals

当期望值等于实际值时执行stage,比如:

when { equals expected: 2, actual: currentBuild.number },

when { equals expected: 2, actual: currentBuild.number }

tag

如果TAG_NAME变量匹配给定的值,则执行stage。比如:

when { tag "release-*" }

如果提供了空值,则在TAG_NAME变量存在时(与buildingTag()相同)将执行stage。

beforeagent

默认情况下,如果定义了某个stage的agent代理,在进入该stageagent 后,该 stagewhen 条件将会被做判断。但是,在when语法块中可以通过 beforeAgent 参数来更改此条件。 如果 beforeAgent 被设置为 true, 那么就会首先对 when 条件进行评估 , 并且只有在 when 条件验证为真时才会进入 agent

pipeline {
    agent none
    stages {
        stage('deploy-pro') {
            agent {
                label "some-label"
            }
            when {
                beforeAgent true
                branch 'master'
            }
            steps {
                echo 'Deploying'
            }
        }
    }
}

该示例表示只有当分支为master时,才会进入deploy-pro 阶段,这样避免了进入agent中拉取代码,从而提高pipeline执行效率。

Parallel

声明式流水线的stage可以在他们内部声明多个嵌套stage,某些条件下可以让它们并行执行。

注意,一个stage必须只有一个 stepsparallel 的stage。 嵌套stage本身不能包含进一步的 parallel stage, 任何包含 parallel 的stage不能包含 agenttools , 因为他们没有相关 steps

另外, 通过添加 failFast true 到包含 parallelstage 中, 当其中一个进程失败时,会强制所有的 parallel 阶段都被终止。

如下示例:

pipeline {
    agent any
    stages {
        stage('Non-Parallel Stage') {
            steps {
                echo 'This stage will be executed first.'
            }
        }
        stage('Parallel Stage') {
            when {
                branch 'master'
            }
            failFast true
            parallel {
                stage('Branch A') {
                    agent {
                        label "for-branch-a"
                    }
                    steps {
                        echo "On Branch A"
                    }
                }
                stage('Branch B') {
                    agent {
                        label "for-branch-b"
                    }
                    steps {
                        echo "On Branch B"
                    }
                }
                stage('Branch C') {
                    agent {
                        label "for-branch-c"
                    }
                    stages {
                        stage('Nested 1') {
                            steps {
                                echo "In stage Nested 1 within Branch C"
                            }
                        }
                        stage('Nested 2') {
                            steps {
                                echo "In stage Nested 2 within Branch C"
                            }
                        }
                    }
                }
            }
        }
    }
}

除了上面的failFast true 方法外,也可以使用parallelsAlwaysFailFast()方法。

pipeline {
    agent any
    options {
        parallelsAlwaysFailFast()
    }
    stages {
        stage('Non-Parallel Stage') {
            steps {
                echo 'This stage will be executed first.'
            }
        }
        stage('Parallel Stage') {
            when {
                branch 'master'
            }
            parallel {
                stage('Branch A') {
                    ......
                }
                stage('Branch B') {
                    ......
                }
                stage('Branch C') {
                    agent {
                        label "for-branch-c"
                    }
                    stages {
                        stage('Nested 1') {
                            steps {
                                echo "....."
                            }
                        }
                        stage('Nested 2') {
                            steps {
                                echo "...."
                            }
                        }
                    }
                }
            }
        }
    }
}

post

post指令可以定义一个或多个steps ,它根据流水线的完成情况而运行。post支持的条件如下:

always

无论流水线或stage的完成状态如何,在 post 部分定义的steps都会运行。

changed

只有当前流水线或stage的完成状态与它之前的运行状态不同时,在 post 部分定义的steps才会运行。

failure

只有当前流水线或stage的完成状态为”failure”,在 post 部分定义的steps才会运行。 通常web UI是红色。

success

只有当前流水线或stage的完成状态为”success”,在 post 部分定义的steps才会运行。常web UI是蓝色或绿色。

unstable

只有当前流水线或stage的完成状态为”unstable”,在 post 部分定义的steps才会运行。通常由于测试失败,向远程服务器拷贝文件时连接服务器失败等原因造成。通常web UI是黄色。

aborted

只有当前流水线或stage的完成状态为”aborted”,在 post 部分定义的steps才会运行, 通常由于流水线被手动的终止。通常web UI是灰色。

了解完post执行的条件,下面看一个示例:

pipeline {
    agent any
    stages {
        stage('test') {
            steps {
                echo 'Hello World'
            }
        }
    }
    post { 
        always { 
            echo 'I will always say Hello again!'
        }

    }
}

该示例表示无论stages执行结果如何,定义的post部分都会运行。

也可以根据执行结果加上判断,比如:

post {
        always {
           script{
              if (currentBuild.currentResult == "ABORTED" || currentBuild.currentResult == "FAILURE" || currentBuild.currentResult == "UNSTABLE" ){
                 emailext(
                subject: "Jenkins build is ${currentBuild.result}: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
                mimeType: "text/html",
                body: """<p>Jenkins build is ${currentBuild.result}: ${env.JOB_NAME} #${env.BUILD_NUMBER}:</p>
                         <p>Check console output at <a href="${env.BUILD_URL}console">${env.JOB_NAME} #${env.BUILD_NUMBER}</a></p>""",
                recipientProviders: [[$class: 'CulpritsRecipientProvider'],
                                     [$class: 'DevelopersRecipientProvider'],
                                     [$class: 'RequesterRecipientProvider']]
            )
               } 
           }  
       }
    }

该示例在流水线执行失败或者强制终止后发送邮件给指定的邮件接收者。

有关声明式语法介绍就到这里,下一节会通过对比来介绍一下脚本式语法的相关内容。